#ifndef ESDL_sprite_h
#define ESDL_sprite_h

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "image.h"
#include <stdbool.h>
#include "../utils/list.h"

/**
 * @struct Sprite
 * @brief Sprite structure
 */
typedef struct EsdlSprite EsdlSprite;

struct EsdlSprite {
    SDL_Surface* surface; //!< A SDL object
    EsdlImage* image; //!< An image ressource
    SDL_Rect visiblePart; //!< A SDL object
    int x; //!< The relative abscissa coordonate
    int y; //!< The relative ordinate coordonate
    bool show; //!< A flag. If true, the sprite is displayed
    char zindex; //!< The zindex of the sprite. The smaller is the number, the more important is the display priority
    bool focus; //!< A flag. If true, the sprite has the focus
    bool over; //!< A flag. If thue, the mouse is over the sprite
    struct EsdlSprite* parent; //!< The parent sprite. NULL if none.
    EsdlLinkedList children; //!< A lincked list of all the sprite's children
    EsdlLinkedList capturingListeners; //!< A lincked list of carturing listeners binded to the sprite
    EsdlLinkedList bubblingListeners; //!< A lincked list of bubbling listeners binded to the sprite
    void* data; //!< Some other datas...
};

/**
 * @brief Create a new empty sprite
 * @param unsigned int width - The width of the sprite
 * @param unsigned int height - The height of the sprite
 * @return A pointer on the new sprite
 */
EsdlSprite* esdlCreateSprite(unsigned width, unsigned height);

/**
 * @brief Create a new sprite from an image file
 * @param char* fileName - The path of the image (bmp, jpg, png, tga, gif, tif, ppm, pbm, pgm, pnm, xpm, xcf, pcx, lbm formats supported)
 * @return A pointer on the new sprite
 */
EsdlSprite* esdlLoadSpriteFromFile(const char* fileName);

/**
 * @brief Create a new sprite from an image ressource
 * @param Image * image - An image ressource loaded in memory
 * @return A pointer on the new sprite
 * @see Function loadImage()
 */
EsdlSprite* esdlLoadSpriteFromImage(EsdlImage* image);

/**
 * @brief Free memory and delete a sprite. Be carefull, only the sprite is deleted, not his children.
 * @param Sprite * sprite - The sprite to delete
 */
void esdlDeleteSprite(EsdlSprite* sprite);

/**
 * @brief Create a new hierarchic link. A sprit can have only one parent
 * @param Sprite * sprite - the sprite
 * @param Sprite * parentSprite - his parent
 * @return true if success
 */
bool esdlSetSpriteParent(EsdlSprite* sprite, EsdlSprite* parentSprite);

/**
 * @brief Set the relative position of the sprite on his parent
 * @param Sprite * sprite
 * @param int x - The abscissa
 * @param int y - The ordinate
 */
void esdlSetSpritePosition(EsdlSprite* sprite, int x, int y);

/**
 * @brief Get the relative abscissa position of the sprite on his parent
 * @param Sprite * sprite
 * @return Get the relative abscissa of the sprite on the parent sprite
 */
int esdlGetSpriteXPosition(EsdlSprite* sprite);

/**
 * @brief Get the relative ordinate position of the sprite on his parent
 * @param Sprite * sprite
 * @return Get the relative ordinate of the sprite on the parent sprite
 */
int esdlGetSpriteYPosition(EsdlSprite* sprite);

/**
 * @param Sprite * sprite
 * @return Return the total width of the sprite (even the hidden parts of the sprite)
 * @see esdlGetVisibleWidth
 */
int esdlGetTotalWidth(const EsdlSprite* sprite);

/**
 * @param Sprite * sprite
 * @return Return the total height of the sprite (even the hidden parts of the sprite)
 * @see esdlGetVisibleHeight
 */
int esdlGetTotalHeight(const EsdlSprite* sprite);

/**
 * @brief Show the sprite
 * @param Sprite * sprite
 */
void esdlShowSprite(EsdlSprite* sprite);

/**
 * @brief Hide the sprite
 * @param Sprite * sprite
 */
void esdlHideSprite(EsdlSprite* sprite);

/**
 * @brief Hide the sprite if it's shown. Show it if it's hided
 * @param Sprite * sprite
 */
void esdlToggleSpriteVisibility(EsdlSprite* sprite);

/**
 * @param Sprite * sprite
 * @return Get the abscissa of the sprite on the window
 */
int esdlgetAbsoluteXPosition(const EsdlSprite* sprite);

/**
 * @param Sprite * sprite
 * @return Get the ordinate of the sprite on the window
 */
int esdlGetAbsoluteYPosition(const EsdlSprite* sprite);

/**
 * @param Sprite * sprite
 * @return Return the width of the visible of the sprite (il a part of a sprite is out of the parent container, this part is not shown)
 * @see esdlGetTotalWidth
 */
int esdlGetVisibleWidth(const EsdlSprite* sprite);

/**
 * @param Sprite * sprite
 * @return Return the height of the visible of the sprite (il a part of a sprite is out of the parent container, this part is not shown)
 * @see esdlGetTotalWidth
 */
int esdlGetVisibleHeight(const EsdlSprite* sprite);

/**
 * @brief Set the zindex og a sprite. The smaller is the number, the less important is the display priority.
 * A sprite with a 1 zindex will be displays onto a sprite with a 2 zindex.
 * The default zindex is 0
 * @param Sprite * sprite
 * @param char zindex
 */
void esdlSetSpriteZIndex(EsdlSprite* sprite, char zIndex);

/**
 * @param Sprite * sprite
 * @return Return the SDL_Surface pointer of the sprite
 */
SDL_Surface* esdlGetSurface(EsdlSprite* sprite);

#endif
